import re
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer
from . import constants
from rest_framework import serializers
from .models import User
from django_redis import get_redis_connection
from rest_framework_jwt.settings import api_settings
from django.core.mail import send_mail
from django.conf import settings
from .models import Address
from goods.models import SKU
from django_redis import get_redis_connection
"""
序列化器有两个:
1, Serializer: 需要自己编写字段
2, ModelSerializer:可以根据模型类生成字段,提供了update,create

注意点:
1,序列化器字段, 两部分组成: User + 自己写的
2,通过fields指定需要反序列化,序列化哪些字段
3,使用write_only通过,字段选项和extra_kwargs指定需要反序列的字段

"""
class RegisterUserSerializer(serializers.ModelSerializer):
    #writer_only只写(只反序列化,不进行序列化操作)
    password2 = serializers.CharField(label="确认密码",min_length=8,max_length=20,write_only=True)
    sms_code = serializers.CharField(label="短信",min_length=6,max_length=6,write_only=True)
    allow = serializers.CharField(label="允许协议",write_only=True)

    #只读(序列化)
    token = serializers.CharField(label="token",read_only=True)
    class Meta:
        model = User

        #指定字段校验
        fields = ("id","username","password","mobile","password2","sms_code","allow","token")

        extra_kwargs = {
            "password":{
                "write_only":True,
                "min_length":8,
                "max_length":20
            },
            "mobile":{
                "write_only": True
            }
        }

    def validate_mobile(self,value):
        if not re.match(r"1[3-9]\d{9}",value):
            raise serializers.ValidationError("手机号格式错误")

        return value

    #单字段校验
    def validate_allow(self, value):
        if value != 'true':
            raise serializers.ValidationError("需要同意")

        return value


    #多字段校验
    def validate(self, attrs):
        #1,获取两次密码
        password = attrs.get("password")
        password2 = attrs.get("password2")

        #2,判断正确性
        if password != password2:
            raise serializers.ValidationError("两次密码不一致")

        #3,获取redis中的短信验证码
        redis_conn = get_redis_connection("code")
        redis_sms_code = redis_conn.get("sms_%s"%attrs.get("mobile"))

        #4,判断redis中的短信验证,过期
        if not redis_sms_code:
            raise serializers.ValidationError("短信验证码过期")

        #5,删除短信验证码,防止使用旧的继续填写(要看产品经理的设计)
        # redis_conn.delete("sms_%s"%attrs["mobiel"])

        #5,判断redis中的短信,和传入的短信,正确性
        if attrs.get("sms_code") != redis_sms_code.decode():
            raise serializers.ValidationError("短信验证码填写错误")

        #6,返回
        return attrs

    #重写create方法,因为有些字段不需要存储到数据库中,比如:password2,sms_code,allow
    def create(self, validated_data):
        """validated_data校验成功之后的结果"""
        print(validated_data)
        #删除数据库中没有的数据
        del validated_data["password2"]
        del validated_data["sms_code"]
        del validated_data["allow"]

        #创建用户对象保存数据
        user = User.objects.create(**validated_data)
        user.set_password(user.password)
        user.save()

        #给用户补充一个 token值
        # 补充生成记录登录状态的token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user.token = token

        #调用父类方法,创建对象
        return user

#用户详情序列化器
class UserDetailSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ("id","username","mobile","email","email_active")


#用户邮箱保存的序列化器
class UserEmailSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ("id","email")

        extra_kwargs = {
            "email":{
                "required":True
            }
        }

    #重写update方法,不仅保存邮箱给用户, 还要发邮件
    def update(self, instance, validated_data):
        """
        :param instance: 用户对象
        :param validated_data:  {email:email}
        :return:
        """
        #1,更新用户的邮箱属性
        email = validated_data["email"]
        instance.email = email
        instance.save()

        #2,发送邮件
        # verify_url = instance.generate_verify_url()
        # html_message = '<a href="%s">点我验证吧</a>'%verify_url
        #参数1, 收到邮件的标题    参数2:文本消息   参数3:发送者是谁,  参数4: 发送给who, 参数5:html内容
        # send_mail('国际美多商城', '', settings.EMAIL_FROM, [email],
        #           html_message=html_message)
        from celery_tasks.email.tasks import send_verify_mail_url
        verify_url = instance.generate_verify_url()
        send_verify_mail_url.delay(email,verify_url)

        #3,返回
        return instance

#用户地址新增序列化器
class AddressSerializer(serializers.ModelSerializer):

    province = serializers.StringRelatedField(read_only=True)
    city = serializers.StringRelatedField(read_only=True)
    district = serializers.StringRelatedField(read_only=True)

    province_id = serializers.IntegerField(label='省ID', required=True)
    city_id = serializers.IntegerField(label='市ID', required=True)
    district_id = serializers.IntegerField(label='区ID', required=True)

    mobile = serializers.RegexField(label='手机号', regex=r'^1[3-9]\d{9}$')

    class Meta:
        model = Address
        exclude = ('user', 'is_deleted', 'create_time', 'update_time')

    #重写create方法,因为前端的数据中没有携带用户编号过来,所以需要重写设置
    def create(self, validated_data):
        """validated_data反序列化之后所有的数据"""

        #设置user之后,交给父亲创建
        validated_data["user"] = self.context['request'].user
        return super().create(validated_data)

#用户地址更新序列化器
class AddressTitleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = ("title",)


class UserBrowserHistorySerializer(serializers.Serializer):
    sku_id = serializers.IntegerField(label="商品编号",min_value=1,required=True)

    def validate_sku_id(self, value):
        #1,根据编号查询商品
        try:
            sku = SKU.objects.get(id=value)
        except SKU.DoesNotExist:
            raise serializers.ValidationError("商品不存在")

        #2,返回
        return value

    #重写create方法,保存商品数据到redis中
    def create(self, validated_data):
        #1,获取商品编号,获取用户编号
        sku_id = validated_data.get("sku_id")
        user_id = self.context["request"].user.id

        #2,获取redis对象
        redis_conn = get_redis_connection("history")

        #3,删除访问的商品编号,如果存在删除
        #参数1: redis中的key,  参数2: 删除全局  参数3: 被删除的值
        redis_conn.lrem("history_%s"%user_id,0,sku_id)

        #4,存储商品编号到redis
        redis_conn.lpush("history_%s"%user_id,sku_id)

        #5,只保留5个数据
        redis_conn.ltrim("history_%s"%user_id,0,4)

        #6,返回数据
        return validated_data


# 修改密码
class ChangePasswordSerializer(serializers.ModelSerializer):
    old_password = serializers.CharField(min_length=8, max_length=20, write_only=True, required=True)
    password2 = serializers.CharField(min_length=8, max_length=20, write_only=True, required=True)

    class Meta:
        model = User
        fields = ['old_password','password','password2']

    def validate(self, attrs):
        old_password = attrs['old_password']
        password = attrs['password']
        password2 = attrs['password2']

        user = self.context['request'].user

        if not user.check_password(old_password):
            raise serializers.ValidationError('旧密码错误')

        if password != password2:
            raise serializers.ValidationError('两次密码不一致')

        return attrs

    def update(self, instance, validated_data):
        instance.set_password(validated_data['password'])
        instance.save()

        return instance



# 找回密码序列化器
class UserPasswordSerializer(serializers.ModelSerializer):
    password2 = serializers.CharField(min_length=8, max_length=20,write_only=True)
    access_token = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['id','password','password2','access_token']
        extra_kwargs = {
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }

    def validate(self, attrs):
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError('两次密码不一致')

        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=constants.SET_PASSWORD_TOKEN_EXPIRES)
        data = serializer.loads(attrs['access_token'])

        user_id = self.context['view'].kwargs['pk']

        if user_id != str(data.get('user_id')):
            raise serializers.ValidationError('无效的access token')

        return attrs

    def update(self, instance, validated_data):
        """
        更新密码
        """
        # 调用django 用户模型类的设置密码方法
        instance.set_password(validated_data['password'])
        instance.save()
        return instance


class UserAccountSerializer(serializers.ModelSerializer):
    text = serializers.CharField(min_length=4,max_length=4,required=True,write_only=True)
    image_code_id = serializers.UUIDField(write_only=True, required=True)
    class Meta:
        model = User
        fields = ['text','image_code_id']

    def validate(self, attrs):

        # 获取图片验证码标识和用户输入的图片验证码内容
        image_code_id = attrs['image_code_id']
        text = attrs['text']

        # 判断60s内是否给手机发送过短信
        mobile = self.context['view'].kwargs['mobile']
        redis_con = get_redis_connection('code')
        send_flag = redis_con.get('send_flag_%s' % mobile)

        if send_flag:
            raise serializers.ValidationError('发送短信过于频繁')

        # 根据`image_code_id`从redis中获取真实的图片验证码文本
        real_image_code = redis_con.get('img_%s' % image_code_id)

        # 删除图片验证码
        try:
            redis_con.delete('img_%s' % image_code_id)
        except Exception:
            pass

        if not real_image_code:
            raise serializers.ValidationError('图片验证码无效')

        # 对比图片验证码
        if text.lower() != real_image_code.decode().lower():
            raise serializers.ValidationError('图片验证码错误')


        return attrs